AWS CloudFormationでNACL設定を入れてみる
はじめに
ネットワークACL(NACL)設定をCloudFormation テンプレートで展開してみます。 使用するCFnリソースの説明と実際の展開例の紹介を行います。
※ 実際には NACLを導入する前に、セキュリティグループによるトラフィック制御で 代用できないか、オンプレ側セキュリティアプライアンスで対応できないか、 など検討すると良いです。
セキュリティグループに関する話は以下ブログに良くまとまっているので参照下さい。
CFnリソース解説
ざっくりとしたイメージは以下の通り。赤字で示した部分が NACL設定で必要なリソースです。
AWS::EC2::NetworkAcl
NACLを新規作成するためのリソースです。 NACLを設定する VPCを指定しましょう。
以下 リソース記述例です。
Nacl: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VpcId Tags: - Key: Name Value: xxx-nacl
ちなみに、これだけだと インバウンド/アウトバウンド通信をすべて拒否する NACLになります。
AWS::EC2::SubnetNetworkAclAssociation
NACL関連付けを行うためのリソースです。 関連付けを行いたいサブネット毎に作成します。
以下 リソース記述例です。
NaclAssoc: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: NetworkAclId: !Ref Nacl SubnetId: !Ref SubnetId
AWS::EC2::NetworkAclEntry
実際の NACLのルール 1つ1つが このリソースに当たります。
マネコンの表記と、実際の CFnリソース記述との関連を表したイメージが以下になります。
各プロパティを以下説明します。
- NetworkAclId
ルールを挿入したいNACLのIDを指定します。
-
Egress
アウトバウンドルールの場合は
true
、インバウンドルールの場合はfalse
を指定します。 -
RuleNumber
ルール番号を指定します。
※ NACLはルール番号の昇順で見ていって、最初にマッチしたルールが適用されます。 設計で注意が必要です。
-
Protocol
IPプロトコルを指定します。以下早見表です。
プロトコル 指定する番号 ICMP 1 TCP 6 UDP 17 すべて -1 - PortRange
UDP/TCP のポート範囲を指定します。
-
Icmp
※
Protocol
で ICMPを選択した場合に必須です。 ICMPコードおよびタイプを記します。以下, Icmpパラメータの記述例です。
# これは Echo Reply (すべての Code) Icmp: Type: 0 Code: -1 # これは Echo Request (すべての Code) Icmp: Type: 8 Code: -1
ICMP Type/Code の詳細は以下参照ください。
- CidrBlock
CIDR表記で IPアドレスレンジを指定します。
-
RuleAction
許可
allow
もしくは 拒否deny
です。
ユースケース/展開例
以下のようなケースを考えます。
要件は以下の通り。 AWSからオンプレへの方向への通信を制御します。
- AWS(VPC)内 通信 や NATGW 経由のアウトバウンド通信 は
すべて許可したい
- オンプレ → AWS への方向の通信は
すべて許可したい
- AWS → オンプレ への方向の通信は基本的に
すべて拒否したい
- ただし オンプレサーバー
192.168.0.200
への通信(TCP/1218ポート
) は業務システムの都合上どうしても利用しないといけないため、許可する
- ただし オンプレサーバー
上記要件を満たす NACLを展開してみましょう。
NACL 設計
NACL設計の際は以下気をつけましょう。
- ルール番号の若い順番に評価されること
- ルール数の上限は 20 (上限緩和申請で 40)
- インバウンドのルール
ルール番号 タイプ プロトコル ポート範囲 送信先 許可/拒否 備考 100 すべてのトラフィック すべて すべて 0.0.0.0/0 ALLOW デフォルトALLOW * すべてのトラフィック すべて すべて 0.0.0.0/0 DENY デフォルトDENY 今回の制御は 「AWSからオンプレへのアウトバウンド通信」がメインなので、 インバウンドルールは触りません。すべて 許可(ALLOW)とします。
-
アウトバウンドのルール
ルール番号 タイプ プロトコル ポート範囲 送信先 許可/拒否 備考 1 すべてのトラフィック すべて すべて 10.0.0.0/16 ALLOW AWS(VPC)内通信 2 カスタムTCPルール TCP 1218 192.168.0.200/32 ALLOW 特定オンプレサーバーへの通信 10 カスタムTCPルール TCP 1024-65535 192.168.0.0/16 ALLOW エフェメラルポート(TCP) 11 カスタムTCPルール UDP 1024-65535 192.168.0.0/16 ALLOW エフェメラルポート(UDP) 12 カスタムICMPルール ICMP Echo Reply 192.168.0.0/16 ALLOW Ping 確認用 50 すべてのトラフィック すべて すべて 192.168.0.0/16 DENY オンプレへの通信 100 すべてのトラフィック すべて すべて 0.0.0.0/0 ALLOW デフォルトALLOW * すべてのトラフィック すべて すべて 0.0.0.0/0 DENY デフォルトDENY 設定したルールの概説は以下の通り。
- ルール番号:1 - AWS(VPC)内通信を許可します
- ルール番号:2 - 特定オンプレサーバーへの通信を許可します
- ルール番号:10,11,12
- 基本的には後述の ルール(50番) で
AWS→オンプレ: (AWSからみて)行きの通信
を拒否しますが、オンプレ→AWS: (AWSからみて)戻りの通信
は許可しないといけません - そのために TCP/UDP では戻り通信に使われるポート(エフェメラルポート)を、 ICMPでは オンプレからの ping 疎通確認を想定して Echo Reply を許可しています
- 基本的には後述の ルール(50番) で
- ルール番号:50 - オンプレへの通信を拒否します
- ルール番号:100 - デフォルトALLOWです。これが無いと NATGW経由アウトバウンドができません
CloudFormation
前述の NACL設計をそのまま CFnテンプレート化しました。 パラメータとして NACLを適用する VPC ID や Subnet IDを指定します。
AWSTemplateFormatVersion: '2010-09-09' Parameters: # プレフィクス Prefix: Type: String Default: sample-env # NACL生成する VPC VpcId: Type: AWS::EC2::VPC::Id # VPC CIDR VpcCidr: Type: String Default: 10.0.0.0/16 # NACL関連付けする サブネット SubnetId: Type: AWS::EC2::Subnet::Id Resources: # ### NACL生成 Nacl: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VpcId Tags: - Key: Name Value: !Sub ${Prefix}-nacl # ### NACLの関連付け NaclAssoc: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: NetworkAclId: !Ref Nacl SubnetId: !Ref SubnetId # ### インバウンドルール # すべて許可 NaclEntryInbound: Type: AWS::EC2::NetworkAclEntry Properties: Egress: false RuleNumber: 100 RuleAction: allow Protocol: -1 CidrBlock: 0.0.0.0/0 NetworkAclId: !Ref Nacl # ### アウトバウンドルール # VPC内はすべてALLOW NaclEntry001: Type: AWS::EC2::NetworkAclEntry Properties: Egress: true RuleNumber: 1 RuleAction: allow Protocol: -1 CidrBlock: !Ref VpcCidr NetworkAclId: !Ref Nacl # 特定サーバーへの通信は ALLOW NaclEntry002: Type: AWS::EC2::NetworkAclEntry Properties: Egress: true RuleNumber: 2 RuleAction: allow Protocol: 6 CidrBlock: 192.168.0.200/32 PortRange: From: 1218 To: 1218 NetworkAclId: !Ref Nacl # オンプレへの戻り通信(TCP/UDP エフェメラルポート)は ALLOW NaclEntry010: Type: AWS::EC2::NetworkAclEntry Properties: Egress: true RuleNumber: 10 RuleAction: allow Protocol: 6 CidrBlock: 192.168.0.0/16 PortRange: From: 1024 To: 65535 NetworkAclId: !Ref Nacl NaclEntry011: Type: AWS::EC2::NetworkAclEntry Properties: Egress: true RuleNumber: 11 RuleAction: allow Protocol: 17 CidrBlock: 192.168.0.0/16 PortRange: From: 1024 To: 65535 NetworkAclId: !Ref Nacl # オンプレへの戻り通信(ping EchoReply)は ALLOW NaclEntry012: Type: AWS::EC2::NetworkAclEntry Properties: Egress: true RuleNumber: 12 RuleAction: allow Protocol: 1 Icmp: Code: -1 Type: 0 CidrBlock: 192.168.0.0/16 NetworkAclId: !Ref Nacl # それ(戻り通信)以外のオンプレへの通信は すべてDENY NaclEntry050: Type: AWS::EC2::NetworkAclEntry Properties: Egress: true RuleNumber: 50 RuleAction: deny Protocol: -1 CidrBlock: 192.168.0.0/16 NetworkAclId: !Ref Nacl # デフォルトのALLOW NaclEntry100: Type: AWS::EC2::NetworkAclEntry Properties: Egress: true RuleNumber: 100 RuleAction: allow Protocol: -1 CidrBlock: 0.0.0.0/0 NetworkAclId: !Ref Nacl
確認
CFn 展開後の設定を見てみます。
- インバウンドのルール
-
アウトバウンドのルール
設計通りの内容になっていました。
おわりに
NACLはステートレスなので戻り通信のことを考えることが大変ですね。 できれば (AWS側は) Security Group、 (オンプレ側は) ステートフル制御対応のNW機器/Firewall で全てステートフルで済ませたいところです。
それら対応が難しい場合は NACLによる設計を検討下さい。 少しでもどなたかのお役に立てば幸いです。
参考
▼ Developers.IO
▼ AWS Document